// P3_OperatorLib.cpp : Defines the exported functions for the DLL application.
#include "stdafx.h"

#define P3LIBAPI extern "C" __declspec(dllexport)

#include "P3_OperatorLib.h"
#include "P3_StateMachine.h"
#include "Lockable.h"

#include <sstream>
#include <cstring>
#include <set>

using namespace std;

P3StateMachine* gpStateMachine = NULL;

typedef set<const char*> MemorySet;
static MemorySet sAllocatedMemory;

// An internal helper function that allocates output string buffers.
static const char* AllocateCopy( const char* inString )
{
	size_t len = ::strlen( inString );
	char* pCopy = new char[len + 1];
	if( pCopy != NULL )
	{
		::strncpy( pCopy, inString, len + 1 );
		sAllocatedMemory.insert( pCopy );
	}
	return pCopy;
}

int __stdcall P3_ReleaseObject(const char* inObject)
{
	if( inObject == NULL )
		return 1;

	MemorySet::iterator i = sAllocatedMemory.find( inObject );
	if( i == sAllocatedMemory.end() )
		return 0;

	sAllocatedMemory.erase( i );
	delete[] inObject;
	return 1;
}


const char* __stdcall P3_GetConnectionInfo(int inIndex)
{
	if( gpStateMachine == NULL )
		return NULL;

	if( inIndex < 0 || inIndex >= gpStateMachine->NumConnections() )
		return NULL;

	struct P3StateMachine::ConnectionInfo info = gpStateMachine->Info( inIndex );
	ostringstream oss;
	oss << "Name: " << info.Name << "\n"
		<< "Address: " << info.Address << "\n"
		<< "Messages received: " << info.MessagesRecv << "\n"
		<< "Messages sent: " << info.MessagesSent << "\n";
	return AllocateCopy( oss.str().c_str() );
}

int __stdcall P3_GetOperatorState()
{
	if(gpStateMachine == NULL)
		return P3_StateUnavailable;
	switch(gpStateMachine->SystemState())
	{
	case P3StateMachine::Idle:
		return P3_StateIdle;
		
	case P3StateMachine::WaitingForConnection:
		return P3_StateStartup;

	case P3StateMachine::Information:
		return P3_StateConnected;

	case P3StateMachine::Resting:
		return P3_StateResting;

	case P3StateMachine::Running:
		return P3_StateRunning;

	default:
		return P3_StateBusy;
	}
}

int __stdcall P3_Startup(const char* moduleList)
{
	if(moduleList == NULL)
		return 0;
	return gpStateMachine->StartUp(moduleList);
}

int __stdcall P3_Shutdown(void)
{
	if(gpStateMachine == NULL)
		return 0;
	gpStateMachine->Shutdown();
	return 1;
}

int __stdcall P3_Initialize()
{
	if(gpStateMachine != NULL)
		return 0;
	gpStateMachine = new P3StateMachine;

	return 1;
}

int __stdcall P3_Dispose()
{
	if( gpStateMachine == NULL)
		return 0;
	delete gpStateMachine;
	gpStateMachine = NULL;

	return 1;
}


int __stdcall P3_SetConfig()
{
	if(gpStateMachine == NULL)
		return 0;
	return gpStateMachine->SetConfig();
}


int __stdcall P3_StartRun()
{
	if(gpStateMachine == NULL)
		return 0;
	return gpStateMachine->StartRun();
}

int __stdcall P3_StopRun()
{
	if(gpStateMachine == NULL)
		return 0;
	return gpStateMachine->StopRun();
}

int __stdcall P3_SetCallback(long EventID, P3_Function inFunction, void* inData)
{
	if(gpStateMachine == NULL) return 0;

	gpStateMachine->SetCallbackFunction(EventID, inFunction);
	gpStateMachine->SetCallbackData(EventID, inData);
	gpStateMachine->SetCallbackContext(EventID, CallbackBase::CallingThread);

	return 1;
}


int __stdcall P3_SetExternalCallback(long inEventID, P3_Function inFcuntion, void* inData)
{
	int result = P3_SetCallback(inEventID, inFcuntion, inData);
	if(result == 1)
		gpStateMachine->SetCallbackContext(inEventID, CallbackBase::MainThread);

	return result;
}

P3_Function __stdcall P3_GetCallbackFunction(long inEventId)
{
	if(gpStateMachine == NULL)
		return NULL;
	return gpStateMachine->CallbackFunction(inEventId);
}

void* __stdcall P3_GetCallbackData(long inEventId)
{
	if( gpStateMachine == NULL)
		return NULL;
	return gpStateMachine->CallbackData(inEventId);
}

int __stdcall P3_GetCallbackIsExternal(long inEventId)
{
	if(gpStateMachine == NULL)
		return 0;
	return gpStateMachine->CallbackContext(inEventId) == CallbackBase::MainThread;
}

int __stdcall P3_CheckPendingCallback()
{
	int result =0;
	if(gpStateMachine != NULL)
		result = gpStateMachine->CheckPendingCallback();

	return result;
}